﻿using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Assertions;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;

namespace KuiHuaBaoDian.Services.Scene {

    /// <summary>
    /// 场景服务
    /// </summary>
    public static class SceneService {

        /// <summary>
        /// 单例
        /// </summary>
        public static ISceneService Instance => m_Instance ??= KHBD.TypeMap.Instantiate<ISceneService>();
        private static ISceneService m_Instance;
    }

    /// <summary>
    /// 场景服务
    /// </summary>
    public interface ISceneService {

        /// <summary>
        /// 加载场景
        /// </summary>
        /// <param name="assetKey">场景资产键</param>
        /// <returns>异步任务</returns>
        UniTask<SceneHandle> Additive(string assetKey);

        // 疑似官方bug，加载时默认不激活会导致addressables加载链无法完成，关注后续情况
        //UniTask Activate(SceneHandle handle);

        /// <summary>
        /// 释放场景
        /// </summary>
        /// <param name="handle">场景句柄</param>
        /// <returns>异步任务</returns>
        UniTask Release(SceneHandle handle);

        /// <summary>
        /// 有場景正在釋放中，此時如果有資源加載，会引发一些不可控的错误，所有使用Addressable加载应该在无场景释放的情况下进，等待场景释放完成后继续加载。
        /// </summary>
        UniTask WaitForReleaseDone();
    }

    [Implement(typeof(ISceneService))]
    internal sealed class KHBD_SceneService : ISceneService, IService {

        void IService.OnApplicationQuit() {
            m_Dictionary.Clear();
        }

        private record SceneRecord(SceneInstance Instance) {
            public bool IsActivate = false;
        }

        private readonly IDictionary<SceneHandle, SceneRecord> m_Dictionary = new Dictionary<SceneHandle, SceneRecord>();

        private bool m_IsReleasing;
        public bool IsReleasing => m_IsReleasing;

        public UniTask WaitForReleaseDone() {
            return KHBD.Context.WaitUntil(() => !m_IsReleasing, CancellationToken.None);
        }

        public async UniTask<SceneHandle> Additive(string assetKey) {
            Assert.IsFalse(string.IsNullOrWhiteSpace(assetKey));

            await WaitForReleaseDone();
            UnityEngine.Debug.Log($"<color=#00DEFF>开始加载</color> {nameof(SceneService)}.{nameof(Additive)}({assetKey})");
            var handle = Addressables.LoadSceneAsync(assetKey, UnityEngine.SceneManagement.LoadSceneMode.Additive);
            await KHBD.Context.WaitUntil(() => handle.IsDone, CancellationToken.None);
            if (handle.IsValid() && handle.Status == AsyncOperationStatus.Succeeded) {
                var result = handle.Result;
                var sceneHandle = new SceneHandle { GUID = Guid.NewGuid() };
                m_Dictionary.Add(sceneHandle, new SceneRecord(result) { IsActivate = true });
                UnityEngine.Debug.Log($"<color=#4CFF98>加载完成</color> {nameof(SceneService)}.{nameof(Additive)}({assetKey})");
                return sceneHandle;
            }
            UnityEngine.Debug.Log($"<color=#FF0032>加载失败</color> {nameof(SceneService)}.{nameof(Additive)}({assetKey})");
            return SceneHandle.None;
        }

        //public async UniTask Activate(SceneHandle handle) {
        //    Assert.IsNotNull(handle);

        //    if (m_Dictionary.TryGetValue(handle, out var record)) {
        //        if (!record.IsActivate) {
        //            record.IsActivate = true;
        //            await record.Instance.ActivateAsync();
        //        }
        //    }
        //}

        public async UniTask Release(SceneHandle handle) {
            Assert.IsFalse(handle.Equals(SceneHandle.None));

            await WaitForReleaseDone();
            if (m_Dictionary.TryGetValue(handle, out var record)) {
                m_Dictionary.Remove(handle);
                m_IsReleasing = true;
                var sceneName = record.Instance.Scene.name;
                UnityEngine.Debug.Log($"<color=#00DEFF>正在释放</color> {nameof(SceneService)}.{nameof(Additive)}({sceneName})");
                var unloadHandle = Addressables.UnloadSceneAsync(record.Instance, UnityEngine.SceneManagement.UnloadSceneOptions.UnloadAllEmbeddedSceneObjects, false);
                await KHBD.Context.WaitUntil(() => unloadHandle.IsDone, CancellationToken.None);
                if (unloadHandle.IsValid() && unloadHandle.Status == AsyncOperationStatus.Succeeded) {
                    await Resources.UnloadUnusedAssets();
                    GC.Collect();
                    Addressables.Release(unloadHandle);
                    UnityEngine.Debug.Log($"<color=#4CFF98>释放完成</color> {nameof(SceneService)}.{nameof(Additive)}({sceneName})");
                } else {
                    UnityEngine.Debug.Log($"<color=#FF0032>加载失败</color> {nameof(SceneService)}.{nameof(Additive)}({sceneName})");
                }
                m_IsReleasing = false;
            }
        }
    }
}
